/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.oimwrapper.testers;

import Thor.API.Operations.tcFormDefinitionOperationsIntf;
import Thor.API.Operations.tcFormInstanceOperationsIntf;
import Thor.API.Operations.tcObjectOperationsIntf;
import Thor.API.tcResultSet;
import com.thortech.util.logging.Logger;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.tree.DefaultMutableTreeNode;
import org.junit.Test;
import org.oimwrapper.connectors.OIMAdapterBase;
import org.oimwrapper.connectors.OIMRemoteClientBase;
import org.oimwrapper.connectors.internal.OIMObjectFormUtilities;
import org.oimwrapper.connectors.internal.OIMUtilityGetter;

/**
 *
 */
public class ClientGenericMappingLoader extends ClientBaseTester {
    
    
    private static final Logger logger = Logger.getLogger(ClientGenericMappingLoader.class.getName());
    //private static final String childRoleTableName = "Lookup.ChildRoleTableName";

    private static OIMAdapterBase apiBase;
    private OIMRemoteClientBase tester;
    
    private tcFormInstanceOperationsIntf formInstOps;
    private tcFormDefinitionOperationsIntf formDefOps;
    private tcObjectOperationsIntf objectOp;
    private OIMObjectFormUtilities objFormUtils;
    
    private String prefix = "";
    
    @Test
    public void mainTest()
    {
        try {
            tester = this.connect();
            apiBase = tester.getUtils();
            formInstOps = (tcFormInstanceOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcFormInstanceOperationsIntf.class);
            formDefOps = (tcFormDefinitionOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcFormDefinitionOperationsIntf.class);
            objectOp = (tcObjectOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcObjectOperationsIntf.class);
            objFormUtils = OIMUtilityGetter.getObjectFormUtilities(logger, objectOp,formInstOps, formDefOps);
        } catch (Exception ex) {
            logger.error("Exception",ex);
            return;
        }
        
        getObjectForm();
        
    }
    
    private void getObjectForm()
    {
        Map<String,Map<String,List<Map>>> resFieldInfo = null;
        try
        {
            //logger.debug("OBJECTS");
            tcResultSet rs = objectOp.findObjects(new HashMap());
            for(int r=0;r<rs.getRowCount();r++)
            {
                rs.goToRow(r);
                String resourceName = rs.getStringValue("Objects.Name");
                logger.debug("Resource:" + resourceName);
                String type = rs.getStringValue("Objects.Type");
                if (type.equalsIgnoreCase("system"))
                    continue;
                String objectTableName = rs.getStringValue("Structure Utility.Table Name");
                
                //getFormData(resourceName);
                
                //if (1 == 1)
                //    continue;
                
                if (objectTableName == null || objectTableName.trim().length() == 0)
                {
                    resFieldInfo = getResourceFormFieldInfo(resourceName,"Provisioning");
                }
                else
                {
                    resFieldInfo = getResourceFormFieldInfo(resourceName,"Approval");
                }
                
                if (resFieldInfo == null)
                {
                    logger.info("No Forms Found for:" + resourceName);
                    continue;
                }
                
                generateMapRecords(resFieldInfo,resourceName,"CREATEUSER");
                //logger.debug("Children:" + c);
                resFieldInfo = getResourceFormFieldInfo(resourceName,"Provisioning");
                if (resFieldInfo == null)
                    continue;
                generateMapRecords(resFieldInfo,resourceName,"ADDROLE");
                generateMapRecords(resFieldInfo,resourceName,"REMOVEROLE");
            }
            
        }
        catch(Exception e)
        {
            logger.error("APIERROR",e);
        }
    }
    
    private void generateMapRecords(Map<String,Map<String,List<Map>>> resFieldInfo,String resourceName,String tranType)
    {
        Map<String,List<Map>> p = resFieldInfo.get("Parent");
        Map<String,List<Map>> c = resFieldInfo.get("Children");
        String parentTableName = null;
        Set<String> keySet = null;
        //logger.debug("FieldInfo for:" + resourceName);
        //logger.debug("Parent:" + p);
        if (p != null)
        {
            keySet = p.keySet();
            for(String k: keySet)
            {
                //logger.debug("Key:" + k);
                parentTableName = k;
                if (tranType.equalsIgnoreCase("CREATEUSER"))
                {
                    List<Map> fields = p.get(k);
                    for(Map<String,String> field : fields)
                    {
                        //logger.debug("Field:" + field);
                        Map tableRec = new HashMap();
                        tableRec.put("resource_name",resourceName);
                        tableRec.put("request_type",tranType);
                        tableRec.put("parent_table_name",parentTableName);
                        tableRec.put("child_table_name","");
                        tableRec.put("column_name",field.get("Structure Utility.Additional Columns.Name"));
                        tableRec.put("column_type",field.get("Structure Utility.Additional Columns.Variant Type"));
                        tableRec.put("column_optional",field.get("OPTIONAL"));
                        tableRec.put("field_label",field.get("Structure Utility.Additional Columns.Field Label"));
                        //logger.debug("Record:" + tableRec);
                        makeSQL(tableRec);
                    }
                }
            }
        }

        if (c != null)
        {
            keySet = c.keySet();
            for(String k : keySet)
            {
                List<Map> fields = c.get(k);
                for(Map<String,String> field : fields)
                {

                    Map tableRec = new HashMap();
                    tableRec.put("resource_name",resourceName);
                    tableRec.put("request_type",tranType);
                    tableRec.put("parent_table_name",parentTableName);
                    tableRec.put("child_table_name",k);
                    tableRec.put("column_name",field.get("Structure Utility.Additional Columns.Name"));
                    tableRec.put("column_type",field.get("Structure Utility.Additional Columns.Variant Type"));
                    tableRec.put("field_label",field.get("Structure Utility.Additional Columns.Field Label"));
                    tableRec.put("column_optional",field.get("OPTIONAL"));
                    //logger.debug("Record:" + tableRec);
                    makeSQL(tableRec);
                }
            }
        }
    }
    
    private void makeSQL(Map record)
    {
        Set<String> keySet = record.keySet();
        //System.out.println("" + keySet);
        StringBuffer hdrBuf = new StringBuffer();
        StringBuffer valBuf = new StringBuffer();
        
        hdrBuf.append("OIMARMID");
        valBuf.append("OIM_ARM_MAPPING_SEQ.NEXTVAL");
        
        boolean first = false;
        for(String k : keySet)
        {
            String v = "'" + record.get(k) + "'";
            
            if (first)
            {
                hdrBuf.append(k);
                valBuf.append(v);
                first = false;
            }
            else
            {
                hdrBuf.append("," + k);
                valBuf.append("," + v);
            }
        }
        System.out.println("INSERT INTO OIM_ARM_MAPPING (" + hdrBuf.toString() + ") values(" + valBuf.toString() + ");");
        
    }
    
    private Map<String,Map<String,List<Map>>> getResourceFormFieldInfo(String resourceName,String processType)
    {
        Map provision = null;
        Map approval = null;
        
        Map<String,Map<String,List<Map>>> fieldMapData = new HashMap<String,Map<String,List<Map>>>();
        
        
        try
        {
            Map[] resourceInfo = this.apiBase.getResourceFormInfo(resourceName);
            
            for(int m=0;m<resourceInfo.length;m++)
            {
                logger.debug("ResForminfo:" + resourceInfo[m]);
                Map ri = resourceInfo[m];
                String type = (String)ri.get("Process Definition.Type");
                if (!type.equalsIgnoreCase(processType))
                    continue;
                if (type.equalsIgnoreCase("Provisioning"))
                    provision = ri;
                if (type.equalsIgnoreCase("Approval"))
                    approval = ri;
                //logger.debug("RI:" + ri);
            }
            
            List<Map> fieldInfo = null;
            
            if (approval != null)
            {
                //logger.debug("Get Object Fields");
                String defKey = (String)approval.get("FORMDEFKEY");
                String ver = (String)approval.get("FORMVER");
                String parentTable = (String)approval.get("FORMNAME");
                //List parentList = new ArrayList();
                fieldInfo = this.objFormUtils.getObjectFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                //parentList.add(fieldInfo);
                Map<String,List<Map>> parentTableFieldInfo = new HashMap<String,List<Map>>();
                parentTableFieldInfo.put(parentTable,fieldInfo);
                
                Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                //logger.debug("Parent");
                //logger.debug("" + fieldInfo);
                //logger.debug("Children");
                //logger.debug("" + childTableFieldInfo);
                fieldMapData.put("Parent",parentTableFieldInfo);
                fieldMapData.put("Children",childTableFieldInfo);
                return fieldMapData;
            }
            if (provision != null)
            {
                //logger.debug("Get Provision Fields");
                String defKey = (String)provision.get("FORMDEFKEY");
                String ver = (String)provision.get("FORMVER");
                String parentTable = (String)provision.get("FORMNAME");
                //List parentList = new ArrayList();
                fieldInfo = this.objFormUtils.getObjectFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                //parentList.add(fieldInfo);
                Map<String,List<Map>> parentTableFieldInfo = new HashMap<String,List<Map>>();
                parentTableFieldInfo.put(parentTable,fieldInfo);
                fieldInfo = this.apiBase.getProcessFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                //logger.debug("Parent");
                //logger.debug("" + fieldInfo);
                //logger.debug("Children");
                //logger.debug("" + childTableFieldInfo);
                fieldMapData.put("Parent",parentTableFieldInfo);
                fieldMapData.put("Children",childTableFieldInfo);
                return fieldMapData;
            }
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
        return null;
    }

    public DefaultMutableTreeNode getFormData(String resourceName)
    {
        logger.debug("in getformdata");
        try
        {
            List<Map> fieldInfo = null;
            DefaultMutableTreeNode top = new DefaultMutableTreeNode();
            Map[] resourceInfo = this.apiBase.getResourceFormInfo(resourceName);
            
            for(int m=0;m<resourceInfo.length;m++)
            {
                //logger.debug("ResForminfo:" + resourceInfo[m]);
                Map ri = resourceInfo[m];
                String type = (String)ri.get("Process Definition.Type");
                
                if (!type.equalsIgnoreCase("Provisioning"))
                    continue;
                String defKey = (String)ri.get("FORMDEFKEY");
                String ver = (String)ri.get("FORMVER");
                String parentTable = (String)ri.get("FORMNAME");
                fieldInfo = this.objFormUtils.getObjectFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                Map<String,List<Map>> parentTableFieldInfo = new HashMap<String,List<Map>>();
                
                parentTableFieldInfo.put(parentTable,fieldInfo);
                DefaultMutableTreeNode p = new DefaultMutableTreeNode(parentTableFieldInfo);
                top.setUserObject(p);
                logger.debug("Parent:" + parentTableFieldInfo);
                
                Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                Set<String> keys = childTableFieldInfo.keySet();
                for(String k : keys)
                {
                    //logger.debug("Key:" + k);
                    List<Map> list = childTableFieldInfo.get(k);
                    Map<String,List<Map>> oneFieldInfo = new HashMap<String,List<Map>>();
                    oneFieldInfo.put(k,list);
                    DefaultMutableTreeNode c = new DefaultMutableTreeNode(oneFieldInfo);
                    top.add(c);
                    recurseChildren(c,objFormUtils.getObjectFormDefinitionKey(k),objFormUtils.getObjectFormVersion(k));
                }
                
                prefix = "";
                showAll2(top);
            }
            
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
        return null;
    }
    
    
    public void showAll(DefaultMutableTreeNode top)
    {
        
        if (top.getChildCount() > 0) { 
            prefix = prefix + ">>>>";
            for (Enumeration e=top.children(); e.hasMoreElements(); ) { 
                DefaultMutableTreeNode n = (DefaultMutableTreeNode)e.nextElement();
                logger.debug(prefix + "Node:" + n.toString());
                if (n.getChildCount() > 0)
                    showAll(n); 
            } 
        }
    }
    
    public void showAll2(DefaultMutableTreeNode top) {
        Enumeration en = ((DefaultMutableTreeNode) top.getRoot()).breadthFirstEnumeration ();
        while (en.hasMoreElements()) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement();
            
            logger.debug(prefix + "Node:" + node.toString());
            if (node.getChildCount() > 0)
                prefix = prefix + ">>>>";
            //showAll(node);
        }
    }


    
    public void recurseChildren(DefaultMutableTreeNode c,long key, int ver)
    {
        try
        {
            Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(key, ver);
            Set<String> keys = childTableFieldInfo.keySet();
            for(String k : keys)
            {
                //logger.debug("Key:" + k);
                List<Map> list = childTableFieldInfo.get(k);
                Map<String,List<Map>> oneFieldInfo = new HashMap<String,List<Map>>();
                oneFieldInfo.put(k,list);
                DefaultMutableTreeNode ch = new DefaultMutableTreeNode(oneFieldInfo);
                c.add(ch);
                recurseChildren(c,objFormUtils.getObjectFormDefinitionKey(k),objFormUtils.getObjectFormVersion(k));
            }
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
    }
}
